#ifndef __COMMON_H_
#define __COMMON_H_

#include <iostream>
#include <cerrno>
#include <cstring>

#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#define PATHNAME "/home/chb/2024_3_8"
#define PROJ_ID 0x20240308

// 共享内存大小一般 建议是4KB的整数倍
// 系统分配共享内存是按4KB为单位的 --- 内存划分内存块的基本单位是page！
// 如果你今天申请4097字节，系统会给你向上取整，但是你能用的还是4097字节。
// 系统给你的，和你能用的，是两码事儿
#define MAX_SIZE 4096

key_t getKey()
{
    // 相同的参数可以获取相同的key！
    key_t key = ftok(PATHNAME, PROJ_ID);

    if(key < 0)
    {
        std::cerr << "errno : " << errno << " srrmsg : " << strerror(errno) << std::endl;
        exit(1);
    }

    return key;

}

int shmHelper(key_t key, int shmflg)
{
    // key是要shmget要设置进共享内存内核数据结构里的属性的
    // 是共享内存的唯一性标识

    // shmid  vs  key
    //   fd   vs  inode

    // shmid相当于fd，是给用户用的
    // key相当于inode，是给内核用的
    int shmid = shmget(key, MAX_SIZE, shmflg);
    if(shmid < 0)
    {
        std::cerr << "errno : " << errno << " srrmsg : " << strerror(errno) << std::endl;
        exit(2);
    }
    return shmid;
}


int getShm(key_t key)
{
    // 获取共享内存
    // 如果不存在则创建之，如果存在则获取之 --- IPC_CREAT
    return shmHelper(key, IPC_CREAT); 

    // IPC_CREAT 也可以改为0
    // return shmHelper(key, 0);   

}

int createShm(key_t key)
{
    // 申请创建共享内存空间
    // 如果存在则报错，不存在则创建之
    return shmHelper(key, IPC_CREAT | IPC_EXCL | 0600);
}

void *shmAttach(int shmid)
{
    // 挂接共享内存空间，0表示读写
    void *p = shmat(shmid, nullptr, 0);
    // shmat出错时会返回(void *)-1
    if((long long)p == -1)    // Linux系统是按64位编址的
    {
        std::cerr << "errno : " << errno << " srrmsg : " << strerror(errno) << std::endl;
        exit(3);
    }
    return p;
}

void shmDetach(const void *shmaddr)
{
    // 取消挂接
    if(shmdt(shmaddr) == -1)
    {
        std::cerr << "errno : " << errno << " srrmsg : " << strerror(errno) << std::endl;
        exit(4);
    }
}


void delShm(int shmid)
{
    // 删除共享内存
    if(shmctl(shmid, IPC_RMID, nullptr) == -1L)
    {
        std::cerr << "errno : " << errno << " srrmsg : " << strerror(errno) << std::endl;
        exit(5);
    }
}


#endif